package com.esunny.springboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @EnableGlobalMethodSecurity(securedEnabled=true) 开启@Secured 注解过滤权限
 * @EnableGlobalMethodSecurity(jsr250Enabled=true) 开启@RolesAllowed 注解过滤权限
 * @EnableGlobalMethodSecurity(prePostEnabled=true) 使用表达式时间方法级别的安全性 4个注解可用
 * -@PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
 * -@PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
 * -@PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果
 * -@PreFilter 允许方法调用,但必须在进入方法之前过滤输入值
 */
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)//prePostEnabled是开启security方法级注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    //安全拦截机制（最重要），注意antMatchers这些子节点的顺序
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//关闭跨站请求伪造（spring security为防止CSRF限制了除了get以外的大多数方法,不然登录请求都请求不了）
                .authorizeRequests()
//                .antMatchers("/r/r1").hasAuthority("p2")  //有p2权限的请求才能通过（权限在UserDetailsServiceImpl中加入了UserDetails里面）
//                .antMatchers("/r/r2").hasAuthority("p2")
                .antMatchers("/oauth/*", "/token/**").permitAll()
                .antMatchers("/swagger-ui.html", "/doc.html").permitAll()//单独放行swagger是不行的，开发时必须全部放行，否则文档界面乱七八糟
                .anyRequest().permitAll()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.NEVER); //禁用session（这样不会下发cookie和session了）
        // .and()
        // .formLogin()//允许表单登录
        // .and()
        // .sessionManagement()
        // .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) //如果需要就创建一个Session（默认），每个登录成功的用户会新建一个Session
        // .and()
        // .logout() //security默认实现了logout退出，设置退出后跳转的页面（可以在这个里面配置清除redis中的数据）
        // .logoutUrl("/logout");
    }
}
